winsafe\gui\windows/
raw_main.rs

1use std::cell::UnsafeCell;
2use std::marker::PhantomPinned;
3use std::pin::Pin;
4use std::sync::Arc;
5
6use crate::co;
7use crate::decl::*;
8use crate::gui::{privs::*, *};
9use crate::prelude::*;
10
11struct RawMainObj {
12	raw_base: RawBase,
13	opts: WindowMainOpts,
14	hchild_prev_focus: UnsafeCell<HWND>,
15	_pin: PhantomPinned,
16}
17
18/// An ordinary main window.
19///
20/// Hierarchy: `BaseWnd` -> `RawBase` -> `RawMain`.
21#[derive(Clone)]
22pub(in crate::gui) struct RawMain(Pin<Arc<RawMainObj>>);
23
24impl RawMain {
25	#[must_use]
26	pub(in crate::gui) fn new(opts: WindowMainOpts) -> Self {
27		let new_self = Self(Arc::pin(RawMainObj {
28			raw_base: RawBase::new(),
29			opts,
30			hchild_prev_focus: UnsafeCell::new(HWND::NULL),
31			_pin: PhantomPinned,
32		}));
33		new_self.default_message_handlers();
34		new_self
35	}
36
37	fn default_message_handlers(&self) {
38		let self2 = self.clone();
39		self.0.raw_base.base().before_on().wm_activate(move |p| {
40			if !p.is_minimized {
41				let hchild_prev_focus = unsafe { &mut *self2.0.hchild_prev_focus.get() };
42				if p.event == co::WA::INACTIVE {
43					if let Some(hwnd_cur_focus) = HWND::GetFocus() {
44						if self2.0.raw_base.base().hwnd().IsChild(&hwnd_cur_focus) {
45							*hchild_prev_focus = hwnd_cur_focus; // save previously focused control
46						}
47					}
48				} else if *hchild_prev_focus != HWND::NULL {
49					hchild_prev_focus.SetFocus(); // put focus back
50				}
51			}
52			Ok(())
53		});
54
55		let self2 = self.clone();
56		self.0.raw_base.base().before_on().wm_set_focus(move |_| {
57			self2.0.raw_base.delegate_focus_to_first_child();
58			Ok(())
59		});
60
61		self.0.raw_base.base().on().wm_nc_destroy(move || {
62			PostQuitMessage(0);
63			Ok(())
64		});
65	}
66
67	#[must_use]
68	pub(in crate::gui) fn raw_base(&self) -> &RawBase {
69		&self.0.raw_base
70	}
71
72	pub(in crate::gui) fn run_main(
73		&self,
74		hinst: &HINSTANCE,
75		cmd_show: Option<co::SW>,
76	) -> AnyResult<i32> {
77		let opts = &self.0.opts;
78		let atom = self.0.raw_base.register_class(
79			hinst,
80			&opts.class_name,
81			opts.class_style,
82			&opts.class_icon,
83			&opts.class_bg_brush,
84			&opts.class_cursor,
85		);
86
87		let sz_screen =
88			SIZE::with(GetSystemMetrics(co::SM::CXSCREEN), GetSystemMetrics(co::SM::CYSCREEN));
89
90		let pt_wnd = POINT::with(
91			sz_screen.cx / 2 - opts.size.0 / 2, // center on screen
92			sz_screen.cy / 2 - opts.size.1 / 2,
93		);
94
95		let mut rc_wnd = RECT {
96			left: pt_wnd.x, // client area, will be adjusted to size with title bar and borders
97			top: pt_wnd.y,
98			right: pt_wnd.x + opts.size.0 as i32,
99			bottom: pt_wnd.y + opts.size.1 as i32,
100		};
101		rc_wnd = AdjustWindowRectEx(rc_wnd, opts.style, opts.menu != HMENU::NULL, opts.ex_style)
102			.expect(DONTFAIL);
103
104		self.0.raw_base.create_window(
105			opts.ex_style,
106			atom,
107			Some(&opts.title),
108			opts.style,
109			POINT::with(rc_wnd.left, rc_wnd.top),
110			SIZE::with(rc_wnd.right - rc_wnd.left, rc_wnd.bottom - rc_wnd.top),
111			None,
112			if opts.menu == HMENU::NULL { IdMenu::None } else { IdMenu::Menu(&opts.menu) },
113			hinst,
114		);
115
116		let hwnd = self.0.raw_base.base().hwnd();
117		hwnd.ShowWindow(cmd_show.unwrap_or(co::SW::SHOW));
118		hwnd.UpdateWindow().expect(DONTFAIL);
119		BaseWnd::run_main_loop(opts.accel_table.as_deref(), opts.process_dlg_msgs) // blocks until window is closed
120	}
121}